#include <iostream>
#include <behaviortree_cpp_v3/behavior_tree.h>
#include <behaviortree_cpp_v3/bt_factory.h>
#include <gtest/gtest.h>
#include <logger/logger.h>

using namespace BT;
using namespace std;

const char *xml_text = R"(
 <root BTCPP_format="4" >
     <BehaviorTree ID="MainTree">
        <Sequence name="root">
            <ThinkRuntimePort   text="{the_answer}"/>
            <SayRuntimePort     message="{the_answer}" />
        </Sequence>
     </BehaviorTree>
 </root>
)";

class ThinkRuntimePort: public BT::SyncActionNode
{
public:
    ThinkRuntimePort(const std::string &name, const BT::NodeConfiguration &config)
        :
        BT::SyncActionNode(name, config)
    {}

    BT::NodeStatus tick() override
    {
        setOutput("text", "The answer is 42");
        return NodeStatus::SUCCESS;
    }
};

class SayRuntimePort: public SyncActionNode
{
public:
    SayRuntimePort(const std::string &name, const NodeConfiguration &config)
        : SyncActionNode(name, config)
    {}

    NodeStatus tick() override
    {
        auto msg = getInput<string>("message");
        if (!msg)
        {
            EASE_INFO("missing required input: %s", msg.error().c_str());
            return NodeStatus::FAILURE;
        }
        EASE_INFO("robot says: %s", msg.value().c_str());
        return NodeStatus::SUCCESS;
    }
};

TEST(behavior_tree_sequence, behavior_tree)
{
    BehaviorTreeFactory factory;

    PortsList thinkPorts = {OutputPort<string>("text")};
    TreeNodeManifest thinkPortManifest = CreateManifest<ThinkRuntimePort>("ThinkRuntimePort", thinkPorts);
    NodeBuilder thinkBuilder = CreateBuilder<ThinkRuntimePort>();
    factory.registerBuilder(thinkPortManifest, thinkBuilder);

    PortsList sayPorts = {InputPort<string>("message")};
    factory.registerNodeType<SayRuntimePort>("SayRuntimePort", sayPorts);

    factory.registerBehaviorTreeFromText(xml_text);
    Tree tree = factory.createTree("MainTree");
    tree.tickRoot();
}
